'''
This demo show the communication interface of MR813 motion control board based on Lcm.
Dependency: 
- robot_control_cmd_lcmt.py
- robot_control_response_lcmt.py
'''
import lcm
import sys
import os
import time
from threading import Thread, Lock

from robot_control_cmd_lcmt import robot_control_cmd_lcmt
from robot_control_response_lcmt import robot_control_response_lcmt



def main():
    Ctrl = Robot_Ctrl()
    Ctrl.run()
    msg = robot_control_cmd_lcmt()

    try:
        msg.mode = 12 # Recovery stand
        msg.gait_id = 0
        msg.life_count += 1 # Command will take effect when life_count update
        Ctrl.Send_cmd(msg)
        Ctrl.Wait_finish(12, 0)
        msg.mode = -1

#上石子路
        msg.mode = 11 # Locomotion
        msg.gait_id = 10 # TROT_FAST:10 TROT_MEDIUM:3 TROT_SLOW:27 自变频:26
        msg.vel_des = [1.6,0.08,0] #forward  left/rightmove  rotate
        msg.duration = 1530 # Zero duration means continuous motion until a new command is used.
                         # Continuous motion can interrupt non-zero duration interpolation motion
        msg.step_height = [0.06, 0.06] # ground clearness of swing leg
        msg.life_count += 1
        msg.rpy_des = [0,0.3,0]

        Ctrl.Send_cmd(msg)
        time.sleep( 3 )

        msg.mode = 11 # Locomotion
        msg.gait_id = 27 # TROT_FAST:10 TROT_MEDIUM:3 TROT_SLOW:27 自变频:26
        msg.vel_des = [0.10,0,0] #forward  left/rightmove  rotate
        msg.duration = 10000 # Zero duration means continuous motion until a new command is used.
                         # Continuous motion can interrupt non-zero duration interpolation motion
        msg.step_height = [0.06, 0.06] # ground clearness of swing leg
        msg.life_count += 1
        msg.rpy_des = [0,0.3,0]

        Ctrl.Send_cmd(msg)
        time.sleep( 12 )

        times_walk = 8000
        times_sleep = 10

        # 直接走的代码
        while True:
            msg.mode = 11 # Locomotion
            msg.gait_id = 27 # TROT_FAST:10 TROT_MEDIUM:3 TROT_SLOW:27 自变频:26
            msg.vel_des = [0.08,-0.02,0] #forward  left/rightmove  rotate
            msg.duration = times_walk # Zero duration means continuous motion until a new command is used.
                            # Continuous motion can interrupt non-zero duration interpolation motion
            msg.life_count += 1
            msg.rpy_des = [0,0.3,0]  #俯仰角设置
            msg.pos_des = [0,0.28,0]  #质心高度
            msg.step_height = [0.06,0.06]
            Ctrl.Send_cmd(msg)
            time.sleep( times_sleep )

            if msg.mode != 12:
                msg.mode = 12 # Recovery stand
                msg.gait_id = 0
                msg.duration = 500
                msg.life_count += 1 # Command will take effect when life_count update
                Ctrl.Send_cmd(msg)
                Ctrl.Wait_finish(12, 0)
                msg.mode = 11

    except KeyboardInterrupt:
        pass
    Ctrl.quit()
    sys.exit()


class Robot_Ctrl(object):
    def __init__(self):
        self.rec_thread = Thread(target=self.rec_responce)
        self.send_thread = Thread(target=self.send_publish)
        self.lc_r = lcm.LCM("udpm://239.255.76.67:7670?ttl=255")
        self.lc_s = lcm.LCM("udpm://239.255.76.67:7671?ttl=255")
        self.cmd_msg = robot_control_cmd_lcmt()
        self.rec_msg = robot_control_response_lcmt()
        self.send_lock = Lock()
        self.delay_cnt = 0
        self.mode_ok = 0
        self.gait_ok = 0
        self.runing = 1


    def run(self):
        self.lc_r.subscribe("robot_control_response", self.msg_handler)
        self.send_thread.start()
        self.rec_thread.start()

    def msg_handler(self, channel, data):
        self.rec_msg = robot_control_response_lcmt().decode(data)
        if(self.rec_msg.order_process_bar >= 95):
            self.mode_ok = self.rec_msg.mode
            print(self.rec_msg.switch_status)
            time.sleep(0.5)
        else:
            self.mode_ok = 0

    def rec_responce(self):
        while self.runing:
            self.lc_r.handle()
            time.sleep( 0.002 )
        

    def Wait_finish(self, mode, gait_id):
        count = 0
        while self.runing and count < 2000: #10s
            if self.mode_ok == mode and self.gait_ok == gait_id:
                return True
            else:
                time.sleep(0.005)
                count += 1

    def send_publish(self):
        while self.runing:
            self.send_lock.acquire()
            if self.delay_cnt > 20: # Heartbeat signal 10HZ, It is used to maintain the heartbeat when life count is not updated
                self.lc_s.publish("robot_control_cmd",self.cmd_msg.encode())
                self.delay_cnt = 0
            self.delay_cnt += 1
            self.send_lock.release()
            time.sleep( 0.005 )

    def Send_cmd(self, msg):
        self.send_lock.acquire()
        self.delay_cnt = 50
        self.cmd_msg = msg
        self.send_lock.release()
            

    def quit(self):
        self.runing = 0
        self.rec_thread.join()
        self.send_thread.join()


# Main function
if __name__ == '__main__':
    main()
